package busterminalweb.authorization;

import busterminal.exception.BusinessException;
import busterminal.exception.DatabaseException;
import busterminal.persistence.jdbc.AbstractJdbcDAO;
import busterminalweb.authorization.service.Role;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * Класс, предназначенный для проверки полномочий пользователей
 */
public class Authorization {

    /**
     * Добавить пользователя в базу данных
     * @param user ссылка на пользователя
     */
    public void createNewUser(User user) {
        Connection connection = AbstractJdbcDAO.getConnection();
        PreparedStatement preparedStatement = null;
        try {
            preparedStatement = connection.prepareStatement("INSERT INTO User (Id, Login, Password, Name, RoleName) VALUES (?, ?, ?, ?, ?)");
            user.setId(AbstractJdbcDAO.getNextId());
            preparedStatement.setInt(1, user.getId());
            preparedStatement.setString(2, user.getLogin());
            preparedStatement.setString(3, user.getPassword());
            preparedStatement.setString(4, user.getName());
            preparedStatement.setString(5, user.getRole().toString());
            preparedStatement.execute();
        } catch (SQLException e) {
            throw new DatabaseException("Cannot create user with login: " + user.getLogin(), e);
        } finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
            } catch (SQLException ex) {
                System.err.println("Cannot close statement");
                ex.printStackTrace(System.err);
            }
        }
    }

    /**
     * Прочитать пользователя из базы данных
     * @param id идентификатор пользователя
     * @return ссылка на пользователя
     */
    public User read(Integer id) {
        Connection connection = AbstractJdbcDAO.getConnection();
        Statement statement = null;
        ResultSet resultSet = null;
        User user = null;
        try {
            statement = connection.createStatement();
            resultSet = statement.executeQuery("SELECT Id, Login, Password, Name, RoleName FROM User WHERE Id=" + id);
            if (resultSet.next()) {
                user = new User();
                user.setId(resultSet.getInt("Id"));
                user.setLogin(resultSet.getString("Login"));
                user.setPassword(resultSet.getString("Password"));
                user.setName(resultSet.getString("Name"));
                user.setRole(Role.valueOf(resultSet.getString("RoleName").toUpperCase()));
            }
        } catch (SQLException e) {
            throw new DatabaseException("Cannot read user with Id=" + id, e);
        } finally {
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
                if (statement != null) {
                    statement.close();
                }
            } catch (SQLException ex) {
                System.err.println("Cannot close statement");
                ex.printStackTrace(System.err);
            }
        }
        if (user == null) {
            throw new BusinessException("User with Id=" + id + " not found");
        }
        return user;
    }

    /**
     * Обновить сведения о пользователе из базы данных
     * @param user ссылка на пользователя
     */
    public void update(User user) {
        Connection connection = AbstractJdbcDAO.getConnection();
        PreparedStatement preparedStatement = null;
        try {
            preparedStatement = connection.prepareStatement("UPDATE User SET Login=?, Password=?, Name=?, RoleName=? WHERE Id=?");
            preparedStatement.setString(1, user.getLogin());
            preparedStatement.setString(2, user.getPassword());
            preparedStatement.setString(3, user.getName());
            preparedStatement.setString(4, user.getRole().toString());
            preparedStatement.setInt(5, user.getId());
            preparedStatement.execute();
        } catch (SQLException e) {
            throw new DatabaseException("Cannot update user with Id=" + user.getId(), e);
        } finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
            } catch (SQLException ex) {
                System.err.println("Cannot close statement");
                ex.printStackTrace(System.err);
            }
        }
    }

    /**
     * Удалить пользователя из базы данных
     * @param user ссылка на пользователя
     */
    public void delete(User user) {
        delete(user.getId());
    }

    /**
     * Удалить пользователя из базы данных
     * @param id идентификатор пользователя
     */
    public void delete(Integer id) {
        Connection connection = AbstractJdbcDAO.getConnection();
        PreparedStatement preparedStatement = null;
        try {
            preparedStatement = connection.prepareStatement("DELETE FROM User WHERE Id=?");
            preparedStatement.setInt(1, id);
            preparedStatement.execute();
        } catch (SQLException e) {
            throw new DatabaseException("Cannot delete user with Id=" + id, e);
        } finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
            } catch (SQLException ex) {
                System.err.println("Cannot close statement");
                ex.printStackTrace(System.err);
            }
        }
    }

    /**
     * Получить список всех пользователей из базы данных
     * @return список пользователей
     */
    public List<User> findAll() {
        Connection connection = AbstractJdbcDAO.getConnection();
        Statement statement = null;
        ResultSet resultSet = null;
        List<User> userList = new ArrayList<User>();
        try {
            statement = connection.createStatement();
            resultSet = statement.executeQuery("SELECT Id FROM User");
            while (resultSet.next()) {
                userList.add(read(resultSet.getInt("Id")));
            }
        } catch (SQLException e) {
            throw new DatabaseException("Cannot read user list", e);
        } finally {
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
                if (statement != null) {
                    statement.close();
                }
            } catch (SQLException ex) {
                System.err.println("Cannot close statement");
                ex.printStackTrace(System.err);
            }
        }
        return userList;
    }

    /**
     * Проверить, есть ли в базе данных заданные логин и пароль
     * @param login логин
     * @param password пароль
     * @return true - пользователь с заданными логином и паролем есть в базе данных, false - такой записи нет
     */
    public boolean isValidLogin(String login, String password) {
        Connection connection = AbstractJdbcDAO.getConnection();
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            statement = connection.createStatement();
            resultSet = statement.executeQuery("SELECT COUNT(*) AS Num FROM User WHERE Login='" + login + "' AND Password='" + password + "'");
            if (resultSet.next()) {
                if (resultSet.getString("Num").equals("1")) {
                    return true;
                }
            }
            return false;
        } catch (SQLException e) {
            throw new DatabaseException("Cannot validate login " + login, e);
        } finally {
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
                if (statement != null) {
                    statement.close();
                }
            } catch (SQLException ex) {
                System.err.println("Cannot close statement");
                ex.printStackTrace(System.err);
            }
        }
    }

    /**
     * Установить роль пользователю
     * @param userId идентификатор пользователя
     * @param role роль пользователя
     */
    public void setRole(Integer userId, Role role) {
        Connection connection = AbstractJdbcDAO.getConnection();
        PreparedStatement preparedStatement = null;
        try {
            preparedStatement = connection.prepareStatement("UPDATE USER SET RoleName=? WHERE Id=?");
            preparedStatement.setString(1, role.toString());
            preparedStatement.setInt(2, userId);
            preparedStatement.execute();
        } catch (SQLException e) {
            throw new DatabaseException("Cannot set role to user with id=" + userId, e);
        } finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
            } catch (SQLException ex) {
                System.err.println("Cannot close statement");
                ex.printStackTrace(System.err);
            }
        }
    }

    /**
     * Получить пользователя из базы данных по заданным логину и паролю
     * @param login логин пользователя
     * @param password парол пользователя
     * @return ссылка на пользователя
     */
    public User getUser(String login, String password) {
        Connection connection = AbstractJdbcDAO.getConnection();
        Statement statement = null;
        ResultSet resultSet = null;
        User user = null;
        try {
            statement = connection.createStatement();
            resultSet = statement.executeQuery("SELECT Id FROM User WHERE Login='" + login + "' AND Password='" + password + "'");
            if (resultSet.next()) {
                user = read(resultSet.getInt("Id"));
            }
            return user;
        } catch (SQLException e) {
            throw new DatabaseException("Cannot validate login " + login, e);
        } finally {
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
                if (statement != null) {
                    statement.close();
                }
            } catch (SQLException ex) {
                System.err.println("Cannot close statement");
                ex.printStackTrace(System.err);
            }
        }
    }

}